package net.towee.model.account.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import net.towee.model.ProfileArea;
import net.towee.model.account.AccountGroup;
import net.towee.model.account.AccountIdentity;
import net.towee.model.account.AccountProfile;
import net.towee.model.account.Connection;
import net.towee.model.account.ConnectionsContainer;
import net.towee.model.account.Gender;
import net.towee.model.account.PrivacyRule;
import net.towee.model.account.PrivacyRulesContainer;
import net.towee.model.account.RuleItem;
import net.towee.model.account.SocialStatus;
import net.towee.model.impl.ProfileContainerImpl;
import net.towee.server.persistence.impl.MongoDbStore;

import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.PostLoad;
import com.google.code.morphia.annotations.Reference;

/**
 * Implementation of account profile container
 * @author c58
 */
@Entity(MongoDbStore.ACCOUNT_PROFILES_COLLECTION)
public class AccountProfileImpl extends ProfileContainerImpl implements AccountProfile,
		ConnectionsContainer, PrivacyRulesContainer {
	
	// Id of account in accounts collection
	@Id private String id;
	
	// Reference to identity of account
	@Reference private AccountIdentity identity;
	
	// Static profile data
	private Date dob;
	private Gender gender;
	private String status;
	private SocialStatus socStatus;
	private String about;
	
	// Profile visability for search
	private boolean visible;
	
	// Connections to user
	private List<Connection> connections;
	
	// Privacy rules
	private List<PrivacyRule> privacy;
	private PrivacyRule searchRule;
	
	public AccountProfileImpl(){}
	public AccountProfileImpl(AccountIdentity identity){
		this.identity = identity;
		this.id = (identity != null) ? identity.getId() : null;
		
		this.connections = new ArrayList<Connection>();
		this.privacy = new ArrayList<PrivacyRule>();
		this.profileAreas = new LinkedList<ProfileArea>();
		this.visible = true;
	}
	
	@PostLoad
	private void createEmptyArrays() {
		if(connections == null)
			connections = new ArrayList<Connection>();
		if(privacy == null)
			privacy = new ArrayList<PrivacyRule>();
		if(profileAreas == null)
			profileAreas = new LinkedList<ProfileArea>();		
	}
	
	/*
	 * Connections
	 */
	@Override
	public ConnectionsContainer getConnections() {
		return this;
	}
	
	@Override
	public void addConnection(Connection conection) {
		this.connections.add(conection);
	}

	@Override
	public void removeConnection(Connection connection) {
		this.removeConnection(connection);
	}

	@Override
	public void removeConnection(int index) {
		this.connections.remove(index);
	}

	@Override
	public int getConnectionIndex(Connection conn) {
		return this.connections.indexOf(conn);
	}

	@Override
	public List<Connection> getConnectinsList() {
		return connections;
	}
	
	@Override
	public Connection getConnection(int i) {
		return connections.get(i);
	}
	
	/*
	 * Getters for static information
	 */
	@Override
	public AccountIdentity getIdentity() {
		return identity;
	}

	@Override
	public Date getDob() {
		return dob;
	}

	@Override
	public Gender getGender() {
		return gender;
	}

	@Override
	public String getStatus() {
		return status;
	}

	@Override
	public SocialStatus getSocialStatus() {
		return socStatus;
	}

	@Override
	public String getLittleAbout() {
		return about;
	}

	@Override
	public void setIdentity(AccountIdentity identity) {
		this.identity = identity;
	}

	@Override
	public void setDob(Date dob) {
		this.dob = dob;
	}

	@Override
	public void setGender(Gender g) {
		this.gender = g;
	}

	@Override
	public void setStatus(String status) {
		this.status = status;
	}

	@Override
	public void setSocialStatus(SocialStatus socstatus) {
		this.socStatus = socstatus;
	}

	@Override
	public void setLittleAbout(String about) {
		this.about = about;
	}

	@Override
	public boolean isVisible() {
		return visible;
	}

	@Override
	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	/*
	 * Rules of privacy
	 */
	@Override
	public PrivacyRulesContainer getProfileRules() {
		return this;
	}
	@Override
	public void addPrivacyRule(PrivacyRule rule) {
		this.privacy.add(rule);
	}
	@Override
	public void deletePrivacyRule(PrivacyRule rule) {
		this.privacy.remove(rule);
	}
	@Override
	public void filterProfile(List<AccountGroup> groups,
			AccountIdentity identity) {
		PrivacyRule filterRule = null;
		
		for(PrivacyRule rule : getRulesList()) {
			if( ( rule.getDestination().toContactsGroup() != null &&
				  rule.getDestination().toContactsGroup().hasContact(identity) ) ||
				( rule.getDestination().toUsersGroup() != null && 
				  groups.contains( rule.getDestination().toUsersGroup()) )) {
				filterRule = rule;
				break;
			}
		}

		if(filterRule != null)
			filterProfile(filterRule);
		else
			filterProfileForSearch();
	}
	@Override
	public void filterProfileForSearch() {
		if(searchRule != null)
			filterProfile(searchRule);
	}
	private void filterProfile(PrivacyRule rule) {
		for(RuleItem item : rule.getItems()) {
			switch(item) {
			case HIDE_DOB:
				this.dob = null;
				break;
			case HIDE_GENDER:
				this.gender = null;
				break;
			case HIDE_STATUS:
				this.status = null;
				break;
			case HIDE_SOCIAL_STATUS:
				this.socStatus = null;
				break;
			case HIDE_CONNECTIONS:
				this.connections = null;
				break;
			case HIDE_ABOUT:
				this.about = null;
				break;
			case HIDE_EXTENDED_PROFILE:
				this.profileAreas = null;
				break;
			}
		}
	}
	@Override
	public List<PrivacyRule> getRulesList() {
		return privacy;
	}
	@Override
	public PrivacyRule getRuleForSearch() {
		return searchRule;
	}
	@Override
	public void setRuleForSearch(PrivacyRule rule) {
		this.searchRule = rule;
	}
	@Override
	public void setConnections(List<Connection> connections) {
		this.connections = connections;
	}
}
